/**
 * Copyright (c) 快宝网络 kuaidihelp.com Co., Ltd. All Rights Reserved 禁止外泄以及用于其它的商业用途
 */

import dayjs from 'dayjs';
import calendar from 'dayjs/plugin/calendar';
import duration from 'dayjs/plugin/duration';
import { isArray, isFunction, isPlainObject, isUndefined } from 'lodash';
import { isBrowser } from 'umi';
import qs from 'qs';

dayjs.extend(duration);
dayjs.extend(calendar);

// 兼容node环境
const doc: any = isBrowser() ? document : { title: '', body: {}, createElement: () => ({}) };

/**
 *
 * @description 注入css
 * @param str
 */
type Where = 'body' | 'head';

export function insertCSS(str: string, d = doc, where: Where = 'head') {
  const style = d.createElement('style');
  const target = d[where] || d.getElementsByTagName(where)[0];
  style.type = 'text/css';
  // @ts-ignore
  if (style.styleSheet) {
    // @ts-ignore
    style.styleSheet.cssText = str;
  } else {
    style.appendChild(d.createTextNode(str));
    target.appendChild(style);
  }
}

/**
 *
 * @descriptions 格式化日期
 * @param val
 * @param opts
 * @returns
 */
interface DateCalendarOpts {
  timer?: boolean;
  link?: string;
  format?: string;
  auto?: boolean;
}

/**
 *
 * @descriptions 格式化距离
 * @param distance 米
 * @returns
 */
export function distanceFormat(distance: number) {
  const d = !distance || distance <= 0 ? 0 : distance;
  if (d < 1000) {
    return `${d}米`;
  }
  return `${(d / 1000).toFixed(1).replace(/\.0$/, '')}公里`;
}

export function dateCalendar(val: string, opts: DateCalendarOpts = {}) {
  if (!val) return '';
  const { timer = true, link = '-', format, auto = true } = opts;
  if (format && !auto) {
    // 非自动格式化，完全按照传入规则格式化
    return dayjs(val).format(format);
  }
  // 自动格式化为当前日期相对应
  // 时间
  const tf = timer ? ' HH:mm' : '';
  // 年份
  const yearFormat = dayjs().isSame(val, 'year') ? '' : `YYYY${link}`;
  // 综合日期
  const dateFormat = format || yearFormat + `MM${link}DD${tf}`;

  const dayFormat = 'YYYY-MM-DD';
  if (dayjs().add(2, 'day').format(dayFormat) === dayjs(val).format(dayFormat)) {
    return '后天' + (tf ? dayjs(val).format(tf) : '');
  }
  const cfg = {
    lastDay: `[昨天]${tf}`,
    sameDay: `[今天]${tf}`,
    nextDay: `[明天]${tf}`,
    lastWeek: dateFormat,
    nextWeek: dateFormat,
    sameElse: dateFormat,
  };
  const m = dayjs(val);
  return val && m.isValid() ? m.calendar(null, cfg) : val;
}

/**
 *
 * @descriptions 时间格式化 D天H小时m分钟；
 * @param ms 毫秒
 * @returns
 */
export function timeFormat(ms: number) {
  if (!ms || ms <= 0) return '0分钟';
  const dateIns = dayjs.duration(ms, 'milliseconds');
  const days = parseInt(`${dateIns.asDays()}`);
  const hasDays = days > 0;
  const hasHours = dateIns.hours() > 0;
  const format = `${hasDays ? 'D天' : ''}${hasHours ? 'H小时' : ''}m分钟`;
  return dateIns.format(format);
}

/**
 *
 * @descriptions 剩余时间
 * @param date
 * @param min
 */

export function timerRemainder(date?: string): string {
  if (!date) return '';
  return timeFormat(dayjs(date).diff(dayjs(), 'milliseconds'));
}

/**
 *
 * @description 文档标题闪动
 * @param title
 */
let docTimer: NodeJS.Timer;
let defaultTitle = doc.title;
let documentTitleLock = false;
function checkDocTitleHasSpace() {
  return doc.title.startsWith('\u200E');
}
function clearDocTimer() {
  if (docTimer) {
    clearInterval(docTimer);
  }
}
function setDefaultTitle() {
  if (!checkDocTitleHasSpace()) {
    defaultTitle = doc.title;
  }
}
/**
 *
 * @description 清空页面标题
 */
export function cleanDocumentTitle() {
  if (!checkDocTitleHasSpace()) {
    doc.title = '\u200E';
  }
}

/**
 *
 * @description 标题闪烁
 * @param title
 * @param lock
 * @returns
 */
export function documentTitleFlashing(title: string = doc.title, lock: boolean = false) {
  if (documentTitleLock) return;
  let times = 0;
  const max = 20;
  documentTitleLock = lock;
  setDefaultTitle();
  clearDocTimer();
  docTimer = setInterval(() => {
    setDefaultTitle();
    doc.title = `\u200E${times % 2 === 0 ? title : ''}`;
    if (times > max) {
      clearDocTimer();
      doc.title = defaultTitle;
      documentTitleLock = false;
    }
    times += 1;
  }, 500);
}

/**
 *
 * @description 文件转换base64
 * @param file
 * @returns
 */
export function fileToBase64Async(file: any): Promise<string> {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function (e) {
      resolve(e.target?.result as string);
    };
  });
}

/**
 *
 * @description 获取文件后缀
 * @param file
 * @returns
 */
export function getFileExt(file: any): string {
  const { name = '' } = file || {};
  const nameMatches = `${name}`.match(/\.[a-zA-Z]+$/);
  return (nameMatches && nameMatches[0]) || '.png';
}
/**
 *
 * @description 文件转换base64，携带后缀
 * @param file
 * @returns
 */
export async function fileToBase64AsyncWithExt(file: any): Promise<{ img: string; ext: string }> {
  const img = await fileToBase64Async(file);
  return {
    img,
    ext: getFileExt(file),
  };
}

/**
 * 将数据以空格分开，并清除不存在的
 * @param arg
 * @returns
 */
export const mergeBySpace = (...arg: any) => {
  const list = [...new Set(arg.filter((item: any) => !!item))];
  return list.length ? list.join(' ') : '';
};

/**
 * 首字母大写 [string,boolean]，是否将其他字符小写
 */
export const firstUpperCase = (str: any, islower?: boolean) => {
  if (typeof str === 'string') {
    const regs = /\b(\w)|\s(\w)/g;
    const str2 = islower ? str.toLowerCase() : str;
    return str2.replace(regs, (m: string) => m.toUpperCase());
  }
  return str;
};

/**
 * 生成随机字符串
 */
export function randomCode(max: number = 16) {
  let str = '';
  let start = 0;
  const fix = [65, 97, 48, 0];
  const specials = 'kb6';
  const fixLength = fix.length;
  const specialsLength = specials.length;
  const randomIndex = (len: number) => {
    return Math.floor(Math.random() * len);
  };
  while (start < max) {
    const fixNum = fix[randomIndex(fixLength)];
    if (fixNum === 0) {
      str += specials[randomIndex(specialsLength)];
    } else {
      const len = fixNum === 48 ? 9 : 26;
      str += String.fromCharCode(randomIndex(len) + fixNum);
    }
    start++;
  }
  return str;
}

/**
 *
 * 提取数据
 * @returns
 */
export const extractData = (data: any, keys: any, restData?: any) => {
  if (!data || !keys || !keys.length) return { ...data };
  const format = (params: any) => {
    const formatted: Record<string, any> = {};
    keys.map((item: any) => {
      let key = item,
        org = item;
      if (isArray(item)) {
        [key, org] = item;
      }
      let value = isFunction(org) ? org(params) : params[org];

      if (!value && restData) {
        value = restData[org];
      }
      if (!isUndefined(value)) {
        formatted[key] = value;
      }
    });
    return formatted;
  };

  if (isArray(data)) {
    return data.map((item: any) => format(item));
  }

  return format(data);
};

/**
 *
 * 加载js
 * @param url
 * @returns
 */
const loadScriptMaps: Record<string, any> = {};
const loadScriptCallbacks: Function[] = [];
function loadScriptRun() {
  while (loadScriptCallbacks.length > 0) {
    const fun = loadScriptCallbacks.shift();
    if (isFunction(fun)) {
      fun();
    }
  }
}
export function loadScript(url: string, timeout: number = 3000): Promise<void> {
  return new Promise((resolve, reject) => {
    loadScriptCallbacks.push(resolve);
    const loadState = loadScriptMaps[url];
    if (loadState) {
      if (loadState === 2) {
        // 已加载，重新执行所有resolve
        loadScriptRun();
      }
      return;
    }
    let timer: NodeJS.Timeout;
    if (timeout > 0) {
      // 超时加载
      timer = setTimeout(reject, timeout);
    }
    loadScriptMaps[url] = 1;
    const script: any = doc.createElement('script');
    script.type = 'text/javascript';
    script.defer = 'defer';
    script.async = 'async';
    if (script.readyState) {
      script.onreadystatechange = () => {
        if (script.readyState == 'loaded' || script.readyState == 'complete') {
          script.onreadystatechange = null;
          clearTimeout(timer);
          loadScriptRun();
          loadScriptMaps[url] = 2;
        }
      };
    } else {
      script.onload = () => {
        clearTimeout(timer);
        loadScriptRun();
        loadScriptMaps[url] = 2;
      };
    }
    script.src = url;
    doc.body.appendChild(script);
  });
}

/**
 *
 * @description 拉平列表
 * @param list
 * @param by
 * @returns
 */
export function flattenDeepList<T>(list: T[], by: string): T[] {
  const flatList: T[] = [];
  const loop = (arr: T[]) => {
    arr.forEach((item: any) => {
      if (isPlainObject(item) && item[by]) {
        const l = item[by];
        const data: Record<string, any> = {};
        Object.keys(item).forEach((k) => {
          if (k === by) return;
          data[k] = item[k];
        });
        flatList.push(data as T);
        loop(l);
      } else {
        flatList.push(item);
      }
    });
  };
  loop(list);
  return flatList;
}

/**
 *
 * @descriptions 检查是否为移动端
 * @returns
 */
export function checkIsMobile() {
  const source = navigator.userAgent || '';
  let isMobile = false;
  if (/mobile|android|iphone|ipad|phone/i.test(source)) {
    isMobile = true;
  }
  return isMobile;
}

/**
 *
 * @descriptions 读取语音文本
 * @param text
 */
export function speechSynthesisUtterance(text: string) {
  const synth = window.speechSynthesis;
  if (!synth) return;
  const words = new SpeechSynthesisUtterance();
  words.text = text;
  words.lang = 'zh-CN';
  synth.speak(words);
}

/**
 *
 * @descriptions 补充参数
 * @param url
 */
export function urlJoinQuery(url: string, query: { [k: string]: any }) {
  return `${url}${url.includes('?') ? '&' : '?'}${qs.stringify(query)}`;
}
